﻿using System;
using System.Collections.Generic;

using System.Text;
using System.Data.SqlClient;
using System.Data;

namespace WP
{
    public class State
    {
        private int id;
        private int objectid = 0;

        public State(int stateid)
        {
            id = stateid;
        }

        public State(int stateid, int objid)
            : this(stateid)
        {
            objectid = objid;
        }

        public int Objectid
        {
            get
            {
                if (objectid == 0)
                    objectid = DataAccess.wp_GetStateObjectID(id);
                return objectid;
            }
        }

        public int Id
        {
            get
            {
                return id;
            }
        }

        /// <summary>
        /// Egy adott állapthoz tartozó binary kinyerése
        /// </summary>
        public object Binary
        {
            get
            {
                return 1;
                //futuretodo  file
            }

        }

        /// <summary>
        /// Az állapothoz tartozó script
        /// </summary>
        public string Script
        {
            get
            {
                return DataAccess.wp_GetScript(id) + Common.SQLBatchSeparator;
            }
        }

        /// <summary>
        /// A state és a paraméterként kapott állapot legutolsó közös állapota
        /// </summary>
        /// <param name="otherState">Az összevetendő állapot</param>
        /// <returns>Az utolsó közös állapot</returns>
        public State CommonBase(State otherState)
        {
            return DataAccess.wp_GetCommonState(id, otherState);
        }

        /// <summary>
        /// Visszatér azzal az állapottal, melyben az adott objektumot utoljára módosították
        /// a mostani állapotig, azaz az adott objektum aktuális állapotát megelőző módosítás
        /// state-je
        /// </summary>
        /// <param name="objid">Az objektum, melynek keressük a legutóbbi módosítását</param>
        /// <returns>A state, melyben előzőleg módosították az objektumot</returns>
        public State LatestVersion(int objid)
        {
            return DataAccess.wp_LatestVersion(objid, id);
        }

        /// <summary>
        /// Visszatér a state objáktumának előző módosítási state-jével
        /// </summary>
        /// <returns>A state objektumának előző módosításának a state-je</returns>
        public State PreviousVersion()
        {
            return LatestVersion(Objectid);
        }

        /// <summary>
        /// Állapotlista, mellyel a megadott állapotba juttatható a rendszer
        /// </summary>
        /// <param name="toState">Az célállapot</param>
        /// <returns>Az állapotlista, melyeket sorrendben végrehajtava
        /// a rendszer a célállapotba kerül</returns>
        public List<State> Differences(State toState)
        {
            List<State> result = new List<State>();
            State Common = CommonBase(toState);
            List<State> reverse = Parents(Common);
          
            reverse.Remove(Common);

            foreach (State item in reverse)
            {
                result.Add(-item);
                result.Add(item.PreviousVersion());
            }
            result.RemoveAll(IsZero);

            List<State> forward = toState.Parents(Common);
        
            forward.RemoveAt(Common);
            forward.Reverse();
            
            result.AddRange(forward);

            List<int> involvedobject = new List<int>();
            List<State> marktodelete = new List<State>();
            for (int i = result.Count - 1; i >= 0; i--)
            {
                if (result[i] > 0)
                {
                    if (involvedobject.Contains(result[i].Objectid))
                    {
                        marktodelete.Add(result[i]);
                    }
                    else
                    {
                        involvedobject.Add(result[i].Objectid);
                    }
                }
                else
                {
                    if (involvedobject.Contains(new State(-result[i]).Objectid))
                    {
                        marktodelete.Add(result[i]);
                    }
                    else
                    {
                        involvedobject.Add(new State(-result[i]).Objectid);
                    }
                }
            }
            foreach (State item in marktodelete)
            {
                result.Remove(item);
            }
            return result;
        }

        /// <summary>
        /// A paraméterként megadott állapotig bejárja a fát, s visszatér a közben érintett
        /// állapotokkal, felfelé haladó sorrendben. A lista tartalmazza magát az állapotot, valamint
        /// a szülőállapotot is
        /// </summary>
        /// <param name="Parent">A szülőállapot, ameddig bejárjuk a fát. Mindenképpen ős legyen</param>
        /// <returns>Az állapotlista, mely az aktuális állapot és az őse között van</returns>
        public List<State> Parents(State Parent)
        {
            return DataAccess.wp_GetParents(id, Parent.id);
        }

        public static implicit operator State(int id)
        {
            return new State(id);
        }

        public static implicit operator int(State state)
        {
            return state.id;
        }

        private static int CompareStates(State x, State y)
        {
            if (x == null)
            {
                if (y == null)
                    return 0;
                else
                    return -1;
            }
            else
            {
                if (y == null)
                    return 1;
                else
                    if (x.Id > y.Id)
                        return 1;
                    else if (x.Id < y.Id)
                        return -1;
                    else
                        return 0;
            }
        }

        private static bool IsZero(State x)
        {
            if (x.Id == 0)
                return true;
            else
                return false;
        }

        public override bool Equals(object obj)
        {
            if (obj is State) return ((State)obj).id == this.id;
            if (obj is int) return ((int)obj)== this.id;
            return base.Equals(obj);
        }
    }
}
